package mutation;

import java.util.List;
import java.util.LinkedList;
import java.util.Map;

import GA.*;
import util.*;
import Operations.*;
public class ChangeInputValue extends MutationStrategy {

	@Override
	public Chromosome mutate(Chromosome individual) {
		List<Operation> ops =individual.getTest();
		List<Integer> opsHasParams=new LinkedList<Integer>();
		for(int i=0;i<ops.size();i++)
			if(ops.get(i) instanceof Invoke){
				Invoke op=(Invoke) ops.get(i);
				final MethodDeclared method =  op.getMethod();
				final Class<?>[] paramsTypes = method.getParameterTypes();
				if(paramsTypes.length!=0)
					opsHasParams.add(i);
			}else
				if (ops.get(i)  instanceof CreateObject){
					CreateObject op=(CreateObject) ops.get(i);
					final ConstructorDeclared consClazz = op.getConstructor();
					final Class<?>[] paramsTypes = consClazz.getParameterTypes();
					if(paramsTypes.length!=0)
						opsHasParams.add(i);

				}
			
				
				
		try {

			while (opsHasParams.size()!=0) {
				int randNum = ValuesGenerator.getRandomInt(opsHasParams.size());
				Operation op = ops.get(opsHasParams.get(randNum));
				if (op instanceof Invoke) {		
						boolean commitedChange= mutantMethodParams((Invoke) op,individual);
					if(commitedChange)
						break;
				}else
					if (op instanceof CreateObject){
						boolean commitedChange=mutantConstructoParams((CreateObject) op,individual);
						if(commitedChange)
							break;

					}

			}
		} catch (Throwable e){
			System.err.println("Change Input Value Class:" + e.getMessage());
		}	

		return individual;
	}
	private boolean mutantMethodParams(Invoke op,Chromosome individual) throws Throwable {
		final MethodDeclared method = op.getMethod();
		final Class<?>[] paramsTypes = method.getParameterTypes();
		String[] p = new String[paramsTypes.length];
		String[] preParams=op.getParams();
		boolean commitedChange=false;
		for(int i = 0; i < p.length; i++) {
			Class<?> clz=paramsTypes[i];
			do {
			if(Filter.isPrimitiveOrStringType(clz)){
				String paType=Filter.PrimitiveGenericConverter(paramsTypes[i].getName());
				if(ValuesGenerator.getBoleean(0.9f)){				
					String pSuggestValue=ValuesGenerator.modifyActualValue(preParams[i],ValuesGenerator.buildValue(clz.getName()),paType);
					p[i]=pSuggestValue;
					}
				else
					p[i] = 	ValuesGenerator.buildValue(clz.getName());
				commitedChange=true;
			}
			else{
				if(GAConfig.NumVarCut==1) break;
					p[i] = Operation.generateRef(method,clz, individual.getReferenceFactory(),individual.getCluster());

				commitedChange=true;
			}
			} while (p[i]==preParams[i]);
		}
		if(commitedChange)
			op.setParams(p);
		return true;
	}
	   private  boolean mutantConstructoParams(CreateObject op,Chromosome individual)throws Throwable {
			final ConstructorDeclared consClazz = op.getConstructor();
			final Class<?>[] paramsTypes = consClazz.getParameterTypes();
			String[] p = new String[paramsTypes.length];
			String[] preParams=consClazz.getParams();
			boolean commitedChange=false;
			for(int i = 0; i < p.length; i++) {
				Class<?> clz=paramsTypes[i];
				do {
				if(Filter.isPrimitiveOrStringType(clz)){
					String paType=Filter.PrimitiveGenericConverter(paramsTypes[i].getName());
					if(ValuesGenerator.getBoleean(0.9f)){
						String pSuggestValue=ValuesGenerator.modifyActualValue(preParams[i],preParams[i],paType);
						p[i]=pSuggestValue;
						}
					else
						p[i] = 	ValuesGenerator.buildValue(clz.getName());
				}
				else{
					if(GAConfig.NumVarCut==1) break;
						//p[i] = Operation.generateRef(method,clz, individual.getReferenceFactory(),individual.getCluster());
					p[i] =gaInfo.getTestCluster().getReference(paramsTypes[i].getName(), gaInfo.getTestCluster().getRefFactory());
					commitedChange=true;
				}
					
				} while (p[i]==preParams[i]);
			}
			if(commitedChange)
				consClazz.setParams(p);
			return true;
		
	   }

	@Override
	public boolean getMutationFlag() {
		return true;
	}
}
